﻿#include "transdialog.h"

#include <QDesktopServices>
#include <QFileDialog>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QRandomGenerator>
#include <QTimer>

#include "ui_transdialog.h"

#define MY_APID 20231120001886702
#define MY_APID_KEY "dQQJhOmCit0OitjI8hgs"

TransDialog::TransDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::TransDialog)
{
    ui->setupUi(this);
    setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);

    m_Manager = new QNetworkAccessManager(this);
    connect(m_Manager, &QNetworkAccessManager::finished, this, &TransDialog::replyFinished);
}

TransDialog::~TransDialog()
{
    delete ui;
}

void TransDialog::setText(const QString &newText)
{
    m_text = newText;
}

/**
 * @brief   重写的保存函数
 * @details 实现了翻译文本的翻译词替换，保存，和保存完毕打开
 */
void TransDialog::accept()
{
    //替换
    if (!m_text.isEmpty()) {
        for (int i = ui->tableWidget->rowCount() - 1; i >= 0; --i) {
            auto item = ui->tableWidget->item(i, 0);
            int position = item->data(StartIndexRole).toInt();    // 得到之前保存的待替换词位置，长度
            int len = item->data(LengthRole).toInt();
            m_text.replace(position, len, ui->tableWidget->item(i, 1)->text());    // 执行替换
        }

        //保存
        QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
                                   "out.txt",
                                   tr("Text files (*.*)"));

        QFile file(fileName);
        if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
            return;

        QTextStream out(&file);
        out << m_text;

        //写入完成后在资源管理器中打开
        while (!out.atEnd()) {
            qDebug()<<"delay !!!";
            delay_ms(10);
        }
        QDesktopServices::openUrl(QUrl(fileName));
    }

    QDialog::accept();
}

/**
 * @brief   提取关键词
 */
void TransDialog::on_pbt_extract_clicked()
{
    auto key = ui->lineEdit_key->text();
    ui->tableWidget->setRowCount(0);

    if (!key.isEmpty()){
//        qDebug()<<key<<m_text.count(key);
        int count = m_text.count(key);
        int index_last = 0;
        for (int i = 0; i < count; ++i) {
            int index = m_text.indexOf(key, index_last);
            int index1 = m_text.indexOf(":\"", index + key.length());
            int index2 = m_text.indexOf("\"", index1 + 2);
            if (index >= 0 && index1 >= 0 && index2 >= 0) {
                auto extract_word = m_text.mid(index1 + 2, index2 - index1 - 2);
//                qDebug()<<i<<extract_word;
                int row = ui->tableWidget->rowCount();
                ui->tableWidget->insertRow(row);
                auto item = new QTableWidgetItem(extract_word);
                ui->tableWidget->setItem(row, 0, item);          // 使用自定义数据记录翻译词位置信息，以备将来的保存
                item->setData(StartIndexRole, index1 + 2);       // 记录待翻译词的起始位置
                item->setData(LengthRole, index2 - index1 - 2);    // 记录待翻译词的长度
                ui->tableWidget->setItem(row, 1, new QTableWidgetItem(""));
            }
            index_last = index2;
        }
    }
}

/**
 * @brief   执行翻译
 */
void TransDialog::on_pbt_trans_clicked()
{
    current_row = 0;
    trans_one(ui->tableWidget->item(current_row, 0)->text());
}

/**
 * @brief   处理翻译结果
 * @details 百度翻译平台传回的结果是一个Json结构体
 *          解析出对应结果即可
 *          为了实现自动连续翻译，中间做了延时处理
 *          延时间隔1s，是受限于百度翻译免费api的限制
 * @param   reply -- 百度api传回的的结果
 */
void TransDialog::replyFinished(QNetworkReply *reply)
{
    QJsonParseError jsonError;
    QByteArray all = reply->readAll();    // 获得api返回值
    qDebug() << all;
    QJsonDocument json = QJsonDocument::fromJson(all, &jsonError);
    QJsonObject object = json.object();
    QString cResult;
    if (object.contains("error_code")) {
        int nResult = object.value("error_code").toInt();
        switch (nResult) {
        case 52001:
            cResult = "52001 请求超时 重试";
            break;
        case 52002:
            cResult = "52002 系统错误 重试";
            break;
        case 54000:
            cResult = "54000 必填参数为空";
            break;
        case 54001:
            cResult = "54001 签名错误";
            break;
        case 54003:
            cResult = "54003 速度过快访问频率受限";
            break;
        case 54004:
            cResult = "54004 账户余额不足";
            break;
        case 54005:
            cResult = "54005 请求频繁";
            break;
        case 58002:
            cResult = "58002 服务关闭";
            break;
        default:
            cResult = "其他错误";
            break;
        }
    } else {
        QJsonArray value = object.value("trans_result").toArray();
        QJsonObject object1 = value.at(0).toObject();
        cResult = object1.value("dst").toString();    // 得到翻译结果
    }

    qDebug() << "翻译结果" << cResult;
    ui->tableWidget->item(current_row, 1)->setText(cResult);
    reply->deleteLater();

    current_row++;
    if (current_row < ui->tableWidget->rowCount()) {
        delay_ms(1000);     //免费api每秒限制翻译1次
        trans_one(ui->tableWidget->item(current_row, 0)->text());
    } else {
        qDebug()<<"翻译完毕";
    }
}

/**
 * @brief   调用百度在线API，实现在线翻译
 * @details 待翻译语种自动检测，目标语种设置为中文
 *          注意，这是一个异步调用，不返回结果
 *          结果QNetworkAccessManager的响应函数中得到
 * @param   cText -- 待翻译短语
 */
void TransDialog::trans_one(const QString &cText)
{
    int salt = QRandomGenerator::global()->bounded(100);
    QString sign = QString("%1%2%3%4").arg(MY_APID).arg(cText).arg(salt).arg(MY_APID_KEY);    // 连接加密文件
    QByteArray str = QCryptographicHash::hash(sign.toUtf8(), QCryptographicHash::Md5);
    QString MD5 = str.toHex();    // 生成md5加密文件
    QString from = "auto";
    QString to = "zh";    // 目标语言为中文，如果需要转换成其它语言可修改此参数，详见https://fanyi-api.baidu.com/product/113
    QString myurl = QString(
                        "http://api.fanyi.baidu.com/api/trans/vip/translate?"
                        "q=%1&from=%2&to=%3&appid=%4"
                        "&salt=%5&sign=%6")
                        .arg(cText)
                        .arg(from)
                        .arg(to)
                        .arg(MY_APID)
                        .arg(salt)
                        .arg(MD5);                   // 连接上传文本
    m_Manager->get(QNetworkRequest(QUrl(myurl)));    // 发送上传；
}

/**
 * @brief   延迟函数
 * @details 调用事件循环实现的延迟，可以实现主线程内不卡顿延时
 * @param   ms -- 延时时间，单位ms
 */
void TransDialog::delay_ms(int ms)
{
    QEventLoop eventloop;
    QTimer::singleShot(ms, &eventloop, SLOT(quit()));
    eventloop.exec();
}

